{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# .NET/C#⾯试题汇总系列：⾯向对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 1.什么是构造函数\n",
    "\n",
    "概念：构造函数的方法名与类型相同、没有放回值类型\n",
    "\n",
    "作用：完成对类的对象初始化\n",
    "\n",
    "创建一个类的新对象时，系统会自动调用该构造函数初始化新对象，如果没有写定义，那么系统会自动提供一个不带任何参数的public构造函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2.class和struct的区别?\n",
    "相同点 都可以实现借口\n",
    "\n",
    "不同点\n",
    "\n",
    "1.class是引用类型\n",
    "\n",
    "2.class允许继承、被继承，struct不允许，只能继承接口\n",
    "\n",
    "3.class可以初始化变量，struct不可以\n",
    "\n",
    "4.class可以有无参的构造函数，struct不可以，必须是有参的构造函数，而且在有参的构造函数必须初始化所有成员\n",
    "\n",
    "使⽤场景 \n",
    "\n",
    "1.Class⽐较适合⼤的和复杂的数据，表现抽象和多级别的对象层次时。 \n",
    "\n",
    "2.Struct适⽤于作为经常使⽤的⼀些数据组合成的新类型，表示诸如点、矩形等主要⽤来存储数据的轻量 级对象时，偏简单值。 \n",
    "\n",
    "3.Struct有性能优势，Class有⾯向对象的扩展优势"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.简述⼀下⾯向对象的三⼤特性？\n",
    "\n",
    "封装、继承、多态。 封装：是通过把对象的属性的实现细节隐藏起来，仅对外提供公共的访问⽅法。\n",
    "\n",
    "继承：是通过⼦类继承基类、继承抽象类、继承接⼝实现的。 \n",
    "\n",
    "多态：是通过重写基类的override ⽅法、重写虚⽅法实现的。 好处是：⽅便维护、易扩展。 缺点是：⽐ ⾯向过程性能低。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 4.构造函数是否能被重写？\n",
    "\n",
    "构造器Constructor不能被继承，因此不能重写，但可以被重载"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 5.抽象类和接⼝有什么区别？\n",
    "\n",
    "相同点：都不能直接实例化 不同点： \n",
    "1.抽象类⽤abstract修饰、接⼝⽤interface修饰 \n",
    "\n",
    "2.抽象类中的⽅法可以实现，也可以不实现，有抽象⽅法的类⼀定要⽤abstract修饰，接⼝中的⽅法不允 许实现 \n",
    "\n",
    "3.抽象类只能单继承，接⼝⽀持多实现 \n",
    "\n",
    "4.抽象类有构造⽅法，接⼝不能有构造⽅法 \n",
    "\n",
    "\n",
    "5.接⼝只负责功能的定义，通过接⼝来规范类的，（有哪些功能），⽽抽象类即负责功能的定义有可以实 现功能（实现了哪些功能）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 6.类的执⾏顺序？\n",
    "执⾏顺序：⽗类，⼦类，静态块，静态字段，⾮静态块，⾮静态字段，构造器，⽅法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 7.接⼝是否可继承接⼝？抽象类是否可实现（implements）接⼝？抽象类是否可继承实现类 （concrete class）？\n",
    "\n",
    "接口可以继承接口，抽象类可以实现接口\n",
    "\n",
    "抽象类可以继承实现类，但前提是实现类必须有明确的构造函数。 [参考](https://blog.csdn.net/qq_44871613/article/details/121281345)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 8.继承最⼤的好处?\n",
    "\n",
    "对父类成员进行重用，增加代码的可读性灵活性。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 9.请说说引⽤和对象?\n",
    "\n",
    "对象和引⽤时分不开的，对象⽣成⼀个地址，放在堆⾥⾯，引⽤则指向这个地址，放在栈⾥⾯"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 10.什么是匿名类，有什么好处？\n",
    "\n",
    "不⽤定义、没有名字的类，使⽤⼀次便可丢弃。好处是简单、随意、临时的。\n",
    "\n",
    "[官方文档](https://docs.microsoft.com/zh-cn/dotnet/csharp/fundamentals/types/anonymous-types)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ID:10010-Name:EdisonChou-Age:25\n"
     ]
    }
   ],
   "source": [
    "var annoyCla1 = new\n",
    "    {\n",
    "        ID = 10010,\n",
    "        Name = \"EdisonChou\",\n",
    "        Age = 25\n",
    "    };\n",
    "\n",
    "    Console.WriteLine(\"ID:{0}-Name:{1}-Age:{2}\", annoyCla1.ID,annoyCla1.Name, annoyCla1.Age);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "####  11.重写和重载的区别?\n",
    "\n",
    "重写⽅法：关键字⽤override修饰，派⽣类重写基类的⽅法，⽅法命名、返回类型，参数必须相同\n",
    "\n",
    "重载⽅法：⽅法名必须相同，参数列表必须不相同，返回类型可以不相同。 \n",
    "\n",
    "作⽤：重写主要是实现⾯向对象的多态性、重载主要是实现实例化不同的对象\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 12.C#中有没有静态构造函数，如果有是做什么⽤的？\n",
    "\n",
    "特点： 静态构造函数既没有访问修饰符，也没有参数。在创建第⼀个实例或引⽤任何静态成员之前，将⾃ 动调⽤静态构造函数来初始化类。⽆法直接调⽤静态构造函数。在程序中，⽤户⽆法控制何时执⾏静态构 造函数。 ⽤途 : 当类使⽤⽇志⽂件时，将使⽤这种构造函数向⽇志⽂件中写⼊项。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 13.怎样理解静态变量？静态成员和⾮静态成员的区别？\n",
    "\n",
    "静态变量属于类，而不属于对象；并对所有对象所享；静态成员在加载类的时候就被加载。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 14.属性能在接⼝中声明吗？\n",
    "\n",
    "可以，不能有访问修饰符，不能初始化赋值"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 15.在项目中为什么使用接口？接口的好处是什么？什么是面向接口开发？\n",
    "\n",
    "接口是一种约束，描述类的公共方法/公共属性，不能有任何实现\n",
    "\n",
    "好处是：结构清晰，类之间通信简单易懂，扩展性好，提高可复用性。\n",
    "\n",
    "面向interface编程，原意是指面向抽象协议编程，实现者在实现时要严格按协议来办"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 16.什么时候⽤重载？什么时候⽤重写？\n",
    "\n",
    "当⼀个类需要⽤不同的实现来做同⼀件事情，此时应该⽤重写，⽽重载是⽤不同的输⼊做同⼀件事情"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 17.静态⽅法可以访问⾮静态变量吗？如果不可以为什么？\n",
    "\n",
    "静态方法和静态变量不是同一生命周期，静态方法属于类，非静态变量属于具体的对象，静态方法和具体的对象没有任何关联"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 18.在.NET中所有可序列话的类都被标记为_?\n",
    "\n",
    "[serializable]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 19.C#中 property 与 attribute的区别，他们各有什么⽤处，这种机制的好处在哪⾥？\n",
    "\n",
    "一个是属性，用于存取类的字段，一个是特性，用于标识类，方法等的附加性质"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 20.当new B() 创建B的实例时，产生什么输出？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "vscode": {
     "languageId": "csharp"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\r\n",
       "<div>\r\n",
       "    <div id='dotnet-interactive-this-cell-24586.Microsoft.DotNet.Interactive.Http.HttpPort' style='display: none'>\r\n",
       "        The below script needs to be able to find the current output cell; this is an easy method to get it.\r\n",
       "    </div>\r\n",
       "    <script type='text/javascript'>\r\n",
       "async function probeAddresses(probingAddresses) {\r\n",
       "    function timeout(ms, promise) {\r\n",
       "        return new Promise(function (resolve, reject) {\r\n",
       "            setTimeout(function () {\r\n",
       "                reject(new Error('timeout'))\r\n",
       "            }, ms)\r\n",
       "            promise.then(resolve, reject)\r\n",
       "        })\r\n",
       "    }\r\n",
       "\r\n",
       "    if (Array.isArray(probingAddresses)) {\r\n",
       "        for (let i = 0; i < probingAddresses.length; i++) {\r\n",
       "\r\n",
       "            let rootUrl = probingAddresses[i];\r\n",
       "\r\n",
       "            if (!rootUrl.endsWith('/')) {\r\n",
       "                rootUrl = `${rootUrl}/`;\r\n",
       "            }\r\n",
       "\r\n",
       "            try {\r\n",
       "                let response = await timeout(1000, fetch(`${rootUrl}discovery`, {\r\n",
       "                    method: 'POST',\r\n",
       "                    cache: 'no-cache',\r\n",
       "                    mode: 'cors',\r\n",
       "                    timeout: 1000,\r\n",
       "                    headers: {\r\n",
       "                        'Content-Type': 'text/plain'\r\n",
       "                    },\r\n",
       "                    body: probingAddresses[i]\r\n",
       "                }));\r\n",
       "\r\n",
       "                if (response.status == 200) {\r\n",
       "                    return rootUrl;\r\n",
       "                }\r\n",
       "            }\r\n",
       "            catch (e) { }\r\n",
       "        }\r\n",
       "    }\r\n",
       "}\r\n",
       "\r\n",
       "function loadDotnetInteractiveApi() {\r\n",
       "    probeAddresses([\"http://10.0.24.17:1000/\", \"http://172.17.0.1:1000/\", \"http://127.0.0.1:1000/\"])\r\n",
       "        .then((root) => {\r\n",
       "        // use probing to find host url and api resources\r\n",
       "        // load interactive helpers and language services\r\n",
       "        let dotnetInteractiveRequire = require.config({\r\n",
       "        context: '24586.Microsoft.DotNet.Interactive.Http.HttpPort',\r\n",
       "                paths:\r\n",
       "            {\r\n",
       "                'dotnet-interactive': `${root}resources`\r\n",
       "                }\r\n",
       "        }) || require;\r\n",
       "\r\n",
       "            window.dotnetInteractiveRequire = dotnetInteractiveRequire;\r\n",
       "\r\n",
       "            window.configureRequireFromExtension = function(extensionName, extensionCacheBuster) {\r\n",
       "                let paths = {};\r\n",
       "                paths[extensionName] = `${root}extensions/${extensionName}/resources/`;\r\n",
       "                \r\n",
       "                let internalRequire = require.config({\r\n",
       "                    context: extensionCacheBuster,\r\n",
       "                    paths: paths,\r\n",
       "                    urlArgs: `cacheBuster=${extensionCacheBuster}`\r\n",
       "                    }) || require;\r\n",
       "\r\n",
       "                return internalRequire\r\n",
       "            };\r\n",
       "        \r\n",
       "            dotnetInteractiveRequire([\r\n",
       "                    'dotnet-interactive/dotnet-interactive'\r\n",
       "                ],\r\n",
       "                function (dotnet) {\r\n",
       "                    dotnet.init(window);\r\n",
       "                },\r\n",
       "                function (error) {\r\n",
       "                    console.log(error);\r\n",
       "                }\r\n",
       "            );\r\n",
       "        })\r\n",
       "        .catch(error => {console.log(error);});\r\n",
       "    }\r\n",
       "\r\n",
       "// ensure `require` is available globally\r\n",
       "if ((typeof(require) !==  typeof(Function)) || (typeof(require.config) !== typeof(Function))) {\r\n",
       "    let require_script = document.createElement('script');\r\n",
       "    require_script.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js');\r\n",
       "    require_script.setAttribute('type', 'text/javascript');\r\n",
       "    \r\n",
       "    \r\n",
       "    require_script.onload = function() {\r\n",
       "        loadDotnetInteractiveApi();\r\n",
       "    };\r\n",
       "\r\n",
       "    document.getElementsByTagName('head')[0].appendChild(require_script);\r\n",
       "}\r\n",
       "else {\r\n",
       "    loadDotnetInteractiveApi();\r\n",
       "}\r\n",
       "\r\n",
       "    </script>\r\n",
       "</div>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x=1,y=0\n"
     ]
    }
   ],
   "source": [
    "class A{\n",
    "\n",
    "    public A()\n",
    "    {\n",
    "        PrintFields();\n",
    "    }\n",
    "    public virtual void PrintFields(){}\n",
    "}\n",
    "class B:A \n",
    "{\n",
    "\n",
    "    int x = 1;\n",
    "    int y;\n",
    "    public B()\n",
    "    {\n",
    "        y=-1;\n",
    "    }\n",
    "    public override void PrintFields()\n",
    "    {\n",
    "        Console.WriteLine(\"x={0},y={1}\",x,y);\n",
    "    }\n",
    "}\n",
    "\n",
    "new B();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 21.能用foreach遍历访问的对象需要实现接口或声明的方法\n",
    "\n",
    "答：IEnumerable 、 GetEnumerator。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "file_extension": ".cs",
   "mimetype": "text/x-csharp",
   "name": "C#",
   "pygments_lexer": "csharp",
   "version": "10.0"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
